bitkeeper revision 1.1041.3.2 (40e41cd2iveMByv37PKjiwl04MigLQ)
authormjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Thu, 1 Jul 2004 14:16:50 +0000 (14:16 +0000)
committermjw@wray-m-3.hpl.hp.com <mjw@wray-m-3.hpl.hp.com>
Thu, 1 Jul 2004 14:16:50 +0000 (14:16 +0000)
Help for defaults files.

.rootkeys
tools/examples/xmdefaults
tools/python/xen/xend/XendClient.py
tools/python/xen/xend/server/cstruct.py [deleted file]
tools/python/xen/xm/create.py
tools/python/xen/xm/help.py [new file with mode: 0644]
tools/python/xen/xm/main.py
tools/python/xen/xm/opts.py

index 40c0fe962f8c20574a32df29a0c0316b46948d89..3cbef2d4210d0931fd64b2360b92e4e5ce51690a 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40c9c469N2-b3GqpLHHHPZykJPLVvA tools/python/xen/xend/server/channel.py
 40c9c469hJ_IlatRne-9QEa0-wlquw tools/python/xen/xend/server/console.py
 40c9c469UcNJh_NuLU0ytorM0Lk5Ow tools/python/xen/xend/server/controller.py
-40c9c469vHh-qLiiubdbKEQbJf18Zw tools/python/xen/xend/server/cstruct.py
 40d83983OXjt-y3HjSCcuoPp9rzvmw tools/python/xen/xend/server/domain.py
 40c9c469yrm31i60pGKslTi2Zgpotg tools/python/xen/xend/server/messages.py
 40c9c46925x-Rjb0Cv2f1-l2jZrPYg tools/python/xen/xend/server/netif.py
 40c9c469LNxLVizOUpOjEaTKKCm8Aw tools/python/xen/xend/sxp.py
 40d05079aFRp6NQdo5wIh5Ly31c0cg tools/python/xen/xm/__init__.py
 40cf2937gKQcATgXKGtNeWb1PDH5nA tools/python/xen/xm/create.py
+40e41cd2w0I4En6qrJn4em8HkK_oxQ tools/python/xen/xm/help.py
 40cf2937isyS250zyd0Q2GuEDoNXfQ tools/python/xen/xm/main.py
 40cf2937PSslwBliN1g7ofDy2H_RhA tools/python/xen/xm/opts.py
 40cf2937Z8WCNOnO2FcWdubvEAF9QQ tools/python/xen/xm/shutdown.py
index f7b2f53c2117eed73013bd3ce3c6078830566100..cf9e9861db9368661b6055e72e3e5b3ed8a32bf9 100644 (file)
@@ -2,17 +2,24 @@
 #============================================================================
 # Python defaults setup for 'xm create'.
 # Edit this file to reflect the configuration of your system.
-# This file expects the variable 'vmid' to be set.
-#============================================================================
-
-try:
-    vmid = int(vmid) # convert to integer
-except:
-    raise ValueError, "Variable 'vmid' must be an integer"
 
-if vmid <= 0:
-    raise ValueError, "Variable 'vmid' must be greater than 0" 
+#============================================================================
 
+# Define script variables here.
+# xm_vars is defined automatically, use xm_vars.var() to define a variable.
+
+def vmid_check(var, val):
+    val = int(val)
+    if val <= 0:
+        raise ValueError
+    return val
+    
+xm_vars.var('vmid',
+            use="Virtual machine id. Integer greater than 0.",
+            check=vmid_check)
+
+# This checks the script variables.
+xm_vars.check()
 
 #----------------------------------------------------------------------------
 # Kernel image file.
index 13dc3dbb1eeac682b1931a51ef9379359782b1ea..12a21c2c9c8507097a1a074255fb5ce35cad9551 100644 (file)
@@ -1,6 +1,11 @@
 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
 """Client API for the HTTP interface on xend.
 Callable as a script - see main().
+
+This API is the 'control-plane' for xend.
+The 'data-plane' is done separately. For example, consoles
+are accessed via sockets on xend, but the list of consoles
+is accessible via this API.
 """
 import sys
 import httplib
@@ -27,6 +32,8 @@ class Foo(httplib.HTTPResponse):
 
 
 def sxprio(sxpr):
+    """Convert an sxpr to a string.
+    """
     io = StringIO()
     sxp.show(sxpr, out=io)
     print >> io
@@ -80,6 +87,12 @@ def eventurl(location, root, id=''):
     return urljoin(location, root, 'event/', id)
 
 def xend_request(url, method, data=None):
+    """Make a request to xend.
+
+    url    xend request url
+    method http method: POST or GET
+    data   request argument data (dict)
+    """
     urlinfo = urlparse.urlparse(url)
     (uproto, ulocation, upath, uparam, uquery, ufrag) = urlinfo
     if DEBUG: print url, urlinfo
@@ -122,20 +135,37 @@ def xend_request(url, method, data=None):
     return val
 
 def xend_get(url, args=None):
+    """Make a xend request using GET.
+    Requests using GET are 'safe' and may be repeated without
+    nasty side-effects.
+    """
     return xend_request(url, "GET", args)
 
 def xend_call(url, data):
+    """Make xend request using POST.
+    Requests using POST potentially cause side-effects and should
+    not be repeated unless it really is wanted to do the side
+    effect again.
+    """
     return xend_request(url, "POST", data)
 
 class Xend:
 
+    """Default location of the xend server."""
     SRV_DEFAULT = "localhost:8000"
+
+    """Default path to the xend root on the server."""
     ROOT_DEFAULT = "/xend/"
 
     def __init__(self, srv=None, root=None):
         self.bind(srv, root)
 
     def bind(self, srv=None, root=None):
+        """Bind to a given server.
+
+        srv  server location (host:port)
+        root server xend root path
+        """
         if srv is None: srv = self.SRV_DEFAULT
         if root is None: root = self.ROOT_DEFAULT
         if not root.endswith('/'): root += '/'
diff --git a/tools/python/xen/xend/server/cstruct.py b/tools/python/xen/xend/server/cstruct.py
deleted file mode 100755 (executable)
index 880931b..0000000
+++ /dev/null
@@ -1,269 +0,0 @@
-import struct
-
-class Struct:
-
-    maxDepth = 10
-
-    base = ['x', 'B', 'H', 'I', 'L', 'Q', 'c', 'h', 'i', 'l', 'q', ]
-
-    sizes = {'B': 1,
-            'H': 2,
-            'I': 4,
-            'L': 4,
-            'Q': 8,
-            'c': 1,
-            'h': 2,
-            'i': 4,
-            'l': 4,
-            'q': 8,
-            'x': 1,
-            }
-
-    formats = {
-        'int8'          : 'B',
-        'int16'         : 'H',
-        'int32'         : 'I',
-        'int64'         : 'Q',
-        'u8'            : 'B',
-        'u16'           : 'H',
-        'u32'           : 'I',
-        'u64'           : 'Q'
-        }
-
-    def typedef(self, name, val):
-        self.formats[name] = val
-
-    def struct(self, name, *f):
-        self.typedef(name, StructInfo(self, f))
-        
-    def getType(self, name):
-        return self.formats[name]
-
-    def format(self, ty):
-        d = 0
-        f = ty
-        while d < self.maxDepth:
-            d += 1
-            f = self.formats[f]
-            if isinstance(f, StructInfo):
-                return f.format()
-            if f in self.base:
-                return f
-        return -1
-
-    def alignedformat(self, ty):
-        fmt = self.format(ty)
-        #print 'alignedformat> %s |%s|' %(ty, fmt)
-        afmt = self.align(fmt)
-        #print 'alignedformat< %s |%s| |%s|' % (ty, fmt, afmt)
-        return afmt
-
-    def align(self, fmt):
-        n1 = 0
-        afmt = ''
-        for a in fmt:
-            n2 = self.getSize(a)
-            m = n1 % n2
-            if m:
-                d = (n2 - m)
-                afmt += 'x' * d
-                n1 += d
-            afmt += a
-            n1 += n2
-        return afmt
-
-    def fmtsize(self, fmt):
-        s = 0
-        for f in fmt:
-            s += self.getSize(f)
-        return s
-
-    def getSize(self, f):
-        return self.sizes[f]
-
-    def pack(self, ty, data):
-        return self.getType(ty).pack(data)
-
-    def unpack(self, ty, data):
-        return self.getType(ty).unpack(data)
-
-    def show(self):
-        l = self.formats.keys()
-        l.sort()
-        for v in l:
-            print "%-35s %-10s %s" % (v, self.format(v), self.alignedformat(v))
-
-
-class StructInfo:
-
-    def __init__(self, s, f):
-        self.fmt = None
-        self.structs = s
-        self.fields = f
-
-    def alignedformat(self):
-        if self.afmt: return self.afmt
-        self.afmt = self.structs.align(self.format())
-        return self.afmt
-    
-    def format(self):
-        if self.fmt: return self.fmt
-        fmt = ""
-        for (ty, name) in self.fields:
-            fmt += self.formatString(ty)
-        self.fmt = fmt
-        return fmt
-
-    def formatString(self, ty):
-        if ty in self.fields:
-            ty = self.fields[ty]
-        return self.structs.format(ty)
-
-    def pack(self, *args):
-        return struct.pack(self.alignedformat(), *args)
-
-    def unpack(self, data):
-        return struct.unpack(self.alignedformat(), data)
-
-types = Struct()
-
-types.typedef('short'         , 'h')
-types.typedef('int'           , 'i')
-types.typedef('long'          , 'l')
-types.typedef('unsigned short', 'H')
-types.typedef('unsigned int'  , 'I')
-types.typedef('unsigned long' , 'L')
-types.typedef('domid_t'       , 'u64')
-types.typedef('blkif_vdev_t'  , 'u16')
-types.typedef('blkif_pdev_t'  , 'u16')
-types.typedef('blkif_sector_t', 'u64')
-
-types.struct('u8[6]',
-             ('u8', 'a1'),
-             ('u8', 'a2'),
-             ('u8', 'a3'),
-             ('u8', 'a4'),
-             ('u8', 'a5'),
-             ('u8', 'a6'))
-             
-types.struct('blkif_fe_interface_status_changed_t',
-    ('unsigned int',    'handle'),
-    ('unsigned int',    'status'),
-    ('unsigned int',    'evtchn'))
-
-types.struct('blkif_fe_driver_status_changed_t',
-    ('unsigned int',    'status'),
-    ('unsigned int',    'nr_interfaces'))
-
-types.struct('blkif_fe_interface_connect_t',
-    ('unsigned int' ,   'handle'),
-    ('unsigned long',   'shmem_frame'))
-
-types.struct('blkif_fe_interface_disconnect_t',
-    ('unsigned int',   'handle'))
-
-types.struct('blkif_extent_t',
-    ('blkif_pdev_t'  , 'device'),
-    ('blkif_sector_t', 'sector_start'),
-    ('blkif_sector_t', 'sector_length'))
-
-types.struct('blkif_be_create_t', 
-    ('domid_t'     ,   'domid'),
-    ('unsigned int',   'blkif_handle'),
-    ('unsigned int',   'status'))
-             
-types.struct('blkif_be_destroy_t',
-    ('domid_t'     ,   'domid'),
-    ('unsigned int',   'blkif_handle'),
-    ('unsigned int',   'status'))
-
-types.struct('blkif_be_connect_t',
-    ('domid_t'      ,  'domid'),
-    ('unsigned int' ,  'blkif_handle'),
-    ('unsigned int' ,  'evtchn'),
-    ('unsigned long',  'shmem_frame'),
-    ('unsigned int' ,  'status'))
-
-types.struct('blkif_be_disconnect_t',
-    ('domid_t'     ,   'domid'),
-    ('unsigned int',   'blkif_handle'),
-    ('unsigned int',   'status'))
-
-types.struct('blkif_be_vbd_create_t', 
-    ('domid_t'     ,   'domid'),         #Q
-    ('unsigned int',   'blkif_handle'),  #I
-    ('blkif_vdev_t',   'vdevice'),       #H
-    ('int'         ,   'readonly'),      #i
-    ('unsigned int',   'status'))        #I
-
-types.struct('blkif_be_vbd_destroy_t', 
-    ('domid_t'     ,   'domid'),
-    ('unsigned int',   'blkif_handle'),
-    ('blkif_vdev_t',   'vdevice'),
-    ('unsigned int',   'status'))
-
-types.struct('blkif_be_vbd_grow_t', 
-    ('domid_t'       , 'domid'),         #Q
-    ('unsigned int'  , 'blkif_handle'),  #I
-    ('blkif_vdev_t'  , 'vdevice'),       #H   
-    ('blkif_extent_t', 'extent'),        #HQQ
-    ('unsigned int'  , 'status'))        #I
-
-types.struct('blkif_be_vbd_shrink_t', 
-    ('domid_t'     ,   'domid'),
-    ('unsigned int',   'blkif_handle'),
-    ('blkif_vdev_t',   'vdevice'),
-    ('unsigned int',   'status'))
-
-types.struct('blkif_be_driver_status_changed_t',
-    ('unsigned int',   'status'),
-    ('unsigned int',   'nr_interfaces'))
-
-types.struct('netif_fe_interface_status_changed_t',
-    ('unsigned int',   'handle'),
-    ('unsigned int',   'status'),
-    ('unsigned int',   'evtchn'),
-    ('u8[6]',          'mac'))
-
-types.struct('netif_fe_driver_status_changed_t',
-    ('unsigned int',   'status'),
-    ('unsigned int',   'nr_interfaces'))
-
-types.struct('netif_fe_interface_connect_t',
-    ('unsigned int',   'handle'),
-    ('unsigned long',  'tx_shmem_frame'),
-    ('unsigned long',  'rx_shmem_frame'))
-
-types.struct('netif_fe_interface_disconnect_t',
-    ('unsigned int',   'handle'))
-
-types.struct('netif_be_create_t', 
-    ('domid_t'     ,   'domid'),
-    ('unsigned int',   'netif_handle'),
-    ('u8[6]'       ,   'mac'),
-    ('unsigned int',   'status'))
-
-types.struct('netif_be_destroy_t',
-    ('domid_t'     ,   'domid'),
-    ('unsigned int',   'netif_handle'),
-    ('unsigned int',   'status'))
-
-types.struct('netif_be_connect_t', 
-    ('domid_t'      ,  'domid'),
-    ('unsigned int' ,  'netif_handle'),
-    ('unsigned int' ,  'evtchn'),
-    ('unsigned long',  'tx_shmem_frame'),
-    ('unsigned long',  'rx_shmem_frame'),
-    ('unsigned int' ,  'status'))
-
-types.struct('netif_be_disconnect_t',
-    ('domid_t'     ,   'domid'),
-    ('unsigned int',   'netif_handle'),
-    ('unsigned int',   'status'))
-
-types.struct('netif_be_driver_status_changed_t',
-    ('unsigned int',   'status'),
-    ('unsigned int',   'nr_interfaces'))
-
-if 1 or __name__ == "__main__":
-    types.show()
index 7819243adb05f7a3456845c573662d2974643807..36bcddef92e5271e0ae62bd26d6bb8f22506faff 100644 (file)
@@ -1,4 +1,5 @@
 # Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
 """Domain creation.
 """
 import string
@@ -15,12 +16,22 @@ from xen.xm.opts import *
 gopts = Opts(use="""[options]
 
 Create a domain.
+
+Domain creation parameters can be set by command-line switches, from
+a python configuration script or an SXP config file. See documentation
+for --defaults, --config. Configuration variables can be set using
+VAR=VAL on the command line. For example vmid=3 sets vmid to 3.
+
 """)
 
 gopts.opt('help', short='h',
          fn=set_true, default=0,
          use="Print this help.")
 
+gopts.opt('help_config',
+          fn=set_true, default=0,
+          use="Print help for configuration file.")
+
 gopts.opt('quiet', short='q',
          fn=set_true, default=0,
          use="Quiet.")
@@ -31,24 +42,40 @@ gopts.opt('path', val='PATH',
 
 gopts.opt('defaults', short='f', val='FILE',
          fn=set_value, default='xmdefaults',
-         use="Use the given default script.")
+         use="""Use the given Python defaults script.
+The defaults script is loaded after arguments have been processed.
+Each command-line option sets a configuration variable named after
+its long option name, and these variables are placed in the
+environment of the script before it is loaded.
+Variables for options that may be repeated have list values.
+Other variables can be set using VAR=VAL on the command line.
+
+After the script is loaded, option values that were not set on the
+command line are replaced by the values set in the script.
+""")
 
 gopts.opt('config', short='F', val='FILE',
          fn=set_value, default=None,
-         use='Domain configuration to use (SXP).')
+         use="""Domain configuration to use (SXP).
+SXP is the underlying configuration format used by Xen.
+SXP configs can be hand-written or generated from Python defaults
+scripts, using the -n (dryrun) option to print the config.
+""")
 
 gopts.opt('load', short='L', val='FILE',
           fn=set_value, default=None,
           use='Domain saved state to load.')
 
-gopts.opt('define', short='D', val='VAR=VAL',
-         fn=set_var, default=None,
-         use="""Set a variable before loading defaults, e.g. '-D vmid=3'
-         to set vmid. May be repeated to set more thanone variable.""")
+#gopts.opt('define', short='D', val='VAR=VAL',
+#         fn=set_var, default=None,
+#         use="""Set a variable before loading defaults, e.g. '-D vmid=3'
+#         to set vmid. May be repeated to set more than one variable.""")
 
 gopts.opt('dryrun', short='n',
          fn=set_true, default=0,
-         use="Dry run - print the config but don't create the domain.")
+         use="""Dry run - print the config but don't create the domain.
+The defaults file is loaded and the SXP configuration is created and printed.         
+""")
 
 gopts.opt('name', short='N', val='NAME',
           fn=set_value, default=None,
@@ -352,7 +379,15 @@ def main(argv):
     args = opts.parse(argv)
     if opts.vals.help:
         opts.usage()
+    if opts.vals.help or opts.vals.help_config:
+        opts.load_defaults(help=1)
+    if opts.vals.help or opts.vals.help_config:
         return
+    # Process remaining args as config variables.
+    for arg in args:
+        if '=' in arg:
+            (var, val) = arg.strip().split('=')
+            gopts.setvar(var.strip(), val.strip())
     if opts.vals.config:
         pass
     else:
diff --git a/tools/python/xen/xm/help.py b/tools/python/xen/xm/help.py
new file mode 100644 (file)
index 0000000..88df441
--- /dev/null
@@ -0,0 +1,82 @@
+# Copyright (C) 2004 Mike Wray <mike.wray@hp.com>
+
+"""Variable definition and help support for Python defaults files.
+"""
+
+import sys
+
+class Vars:
+    """A set of configuration variables.
+    """
+
+    def __init__(self, name, help, env):
+        """Create a variable set.
+
+        name name of the defaults file
+        help help flag
+        env  local environment
+        """
+        self.name = name
+        self.help = help
+        self.env = env
+        self.vars = []
+
+    def var(self, name, use=None, check=None):
+        """Define a configuration variable.
+        If provided, the check function will be called as check(var, val)
+        where var is the variable name and val is its value (string).
+        It should return a new value for the variable, or raise ValueError if
+        the value is not acceptable.
+
+        name  variable name
+        use   variable usage string
+        check variable check function
+        """
+        self.vars.append(Var(name, use, check))
+
+    def check(self):
+        """Execute the variable checks or print help, depending on the value
+        of the help flag passed to the constructor.
+        """
+        if self.help:
+            self.doHelp()
+        else:
+            for v in self.vars:
+                v.doCheck(self.env)
+
+    def doHelp(self, out=sys.stderr):
+        """Print help for the variables.
+        """
+        if self.vars:
+            print >>out, "\nConfiguration variables for %s:\n" % self.name
+            for v in self.vars:
+                v.doHelp(out)
+            print >>out
+
+class Var:
+    """A single variable.
+    """
+
+    def __init__(self, name, use, check):
+        """Create a variable.
+
+        name  variable name
+        use   variable use string
+        check variable value check function
+        """
+        self.name = name
+        self.use = use or ''
+        self.check = check
+
+    def doCheck(self, env):
+        """Execute the check and set the variable to the new value.
+        """
+        if not self.check: return
+        env[self.name] = self.check(self.name, env.get(self.name))
+
+    def doHelp(self, out):
+        """Print help for the variable.
+        """
+        print >>out, "%-12s" % self.name, self.use
+
+        
index 3ab5d23cf756f6ea326a1f775c4105b307898d75..97a36f6711db871ab91940ce01408e5622ce141c 100644 (file)
@@ -5,10 +5,12 @@ import os
 import os.path
 import sys
 from getopt import getopt
+import socket
 
 from xen.xend import PrettyPrint
 from xen.xend import sxp
 from xen.xend.XendClient import server
+from xen.xend.XendClient import main as xend_client_main
 from xen.xm import create, shutdown
 
 class Prog:
@@ -65,6 +67,13 @@ class Xm:
         sys.exit(1)
 
     def main(self, args):
+        try:
+            self.main_call(args)
+        except socket.error, ex:
+            print >>sys.stderr, ex
+            self.err("Error connecting to xend, is xend running?")
+
+    def main_call(self, args):
         """Main entry point. Dispatches to the progs.
         """
         self.name = args[0]
@@ -444,5 +453,21 @@ class ProgConsole(Prog):
 
 xm.prog(ProgConsole)
 
+class ProgCall(Prog):
+    name = "call"
+    info = "Call xend api functions."
+
+    def help (self, args):
+        print "call fn argss..."
+        print """
+        Call a xend HTTP API function. The leading 'xend_' on the function
+can be omitted. See xen.xend.XendClient for the API functions.
+"""
+
+    def main(self, args):
+        xend_client_main(args)
+
+xm.prog(ProgCall)
+
 def main(args):
     xm.main(args)
index eb07936f1e2aee8e313b030e950703087e223fd9..25f11abad2d4de2830f83d3f7ae5c3072281cd23 100644 (file)
@@ -259,7 +259,7 @@ class Opts:
         for opt in self.options:
             opt.show()
 
-    def load_defaults(self):
+    def load_defaults(self, help=0):
         """Load a defaults script. Assumes these options set:
         'path'    search path
         'default' script name
@@ -270,12 +270,12 @@ class Opts:
             else:
                 p = self.vals.defaults
             if os.path.exists(p):
-                self.load(p)
+                self.load(p, help)
                 break
         else:
             self.err("Cannot open defaults file %s" % self.vals.defaults)
 
-    def load(self, defaults, help=0):
+    def load(self, defaults, help):
         """Load a defaults file. Local variables in the file
         are used to set options with the same names.
         Variables are not used to set options that are already specified.
@@ -290,11 +290,17 @@ class Opts:
         cmd = '\n'.join(["import sys",
                          "import os",
                          "import os.path",
-                         "import xen.util.ip",
+                         "from xen.xm.help import Vars",
+                         "from xen.util import ip",
                          "xm_file = '%s'" % defaults,
-                         "xm_help = %d" % help ])
+                         "xm_help = %d" % help,
+                         "xm_vars = Vars(xm_file, xm_help, locals())",
+                         ])
         exec cmd in globals, locals
-        execfile(defaults, globals, locals)
+        try:
+            execfile(defaults, globals, locals)
+        except:
+            if not help: raise
         if help: return
         # Extract the values set by the script and set the corresponding
         # options, if not set on the command line.